home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / irsim-ca.2 / irsim-ca / irsim-cap-9.2 / src / irsim / config.c < prev    next >
C/C++ Source or Header  |  1995-01-19  |  14KB  |  538 lines

  1. /* 
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     ********************************************************************* 
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include "defs.h"
  17. #include "net.h"
  18. #include "globals.h"
  19.  
  20.  
  21. /*
  22.  * electrical parameters used for deriving capacitance info for charge
  23.  * sharing.  Default values aren't for any particular process, but are
  24.  * self-consistent.
  25.  *    Area capacitances are all in pfarads/sq-micron units.
  26.  *    Perimeter capacitances are all in pfarads/micron units.
  27.  */
  28. public    double  CM2A = .00000;    /* 2nd metal capacitance -- area */
  29. public    double  CM2P = .00000;    /* 2nd metal capacitance -- perimeter */
  30. public    double  CMA = .00003;    /* 1st metal capacitance -- area */
  31. public    double  CMP = .00000;    /* 1st metal capacitance -- perimeter */
  32. public    double  CPA = .00004;    /* poly capacitance -- area */
  33. public    double  CPP = .00000;    /* poly capacitance -- perimeter */
  34. public    double  CDA = .00010;    /* n-diffusion capacitance -- area */
  35. public    double  CDP = .00060;    /* n-diffusion capacitance -- perimeter */
  36. public    double  CPDA = .00010;    /* p-diffusion capacitance -- area */
  37. public    double  CPDP = .00060;    /* p-diffusion capacitance -- perimeter */
  38. public    double  CGA = .00040;    /* gate capacitance -- area */
  39.                 /* the following are computed from above */
  40. public    double    CTDW;        /* xtor diff-width capacitance -- perimeter */
  41. public    double    CTDE;        /* xtor diff-extension cap. -- perimeter */
  42. public    double    CTGA;        /* xtor gate capacitance -- area */
  43.  
  44. public    double  LAMBDA = 2.5;      /* microns/lambda */
  45. public    double  LAMBDA2 = 6.25;      /* LAMBDA**2 */
  46. public    long    LAMBDACM = 250;      /* centi-microns/lambda */
  47. public    double  LOWTHRESH = 0.3;  /* low voltage threshold, normalized units */
  48. public    double  HIGHTHRESH = 0.8; /* high voltage threshold,normalized units */
  49. public    double  DIFFEXT = 0;      /* width of source/drain diffusion */
  50.  
  51. public    int    config_flags = 0;
  52.  
  53. #define    CM_M    (100.0)        /* centimicrons per micron */
  54.  
  55. /* values of config_flags */
  56.  
  57.  
  58. public
  59. #define    TDIFFCAP    0x1    /* set if DIFFPERIM or DIFFEXTF are true    */
  60.  
  61. #define    CNTPULLUP    0x2    /* set if capacitance from gate of pullup   */
  62.                 /* should be included.                */
  63.  
  64. #define    DIFFPERIM    0x4    /* set if diffusion perimeter does not         */
  65.                 /* include sources/drains of transistors.   */
  66.  
  67. #define    SUBPAREA    0x8    /* set if poly over xistor doesn't make a   */
  68.                 /* capacitor.                    */
  69.  
  70. #define    DIFFEXTF    0x10    /* set if we should add capacitance due to  */
  71.                 /* diffusion-extension of source/drain.        */
  72.  
  73.  
  74. typedef struct    /* table translating parameters to its associated names */
  75.   {
  76.     char      *name;
  77.     int       flag;
  78.     double    *dptr;
  79.   } pTable;
  80.  
  81. private    pTable  parms[] = 
  82.   {
  83.     "capm2a",        0x0,    &CM2A,
  84.     "capm2p",        0x0,    &CM2P,
  85.     "capma",        0x0,    &CMA,
  86.     "capmp",        0x0,    &CMP,
  87.     "cappa",        0x0,    &CPA,
  88.     "cappp",        0x0,    &CPP,
  89.     "capda",        0x0,    &CDA,
  90.     "capdp",        0x0,    &CDP,
  91.     "cappda",        0x0,    &CPDA,
  92.     "cappdp",        0x0,    &CPDP,
  93.     "capga",        0x0,    &CGA,
  94.     "lambda",        0x0,    &LAMBDA,
  95.     "lowthresh",    0x0,    &LOWTHRESH,
  96.     "highthresh",   0x0,    &HIGHTHRESH,
  97.     "diffperim",    DIFFPERIM,    NULL,
  98.     "cntpullup",    CNTPULLUP,    NULL,
  99.     "subparea",        SUBPAREA,    NULL,
  100.     "diffext",        DIFFEXTF,    &DIFFEXT,
  101.     NULL,        0x0,    NULL
  102.   };
  103.  
  104.  
  105. #define    LSIZE        500    /* max size of parameter file input line */
  106. #define    MAXARGS        10    /* max number of arguments in line */
  107.  
  108. private    int     lineno;        /* current line number */
  109. private    char    *currfile;    /* current input file */
  110. private    int     nerrs = 0;    /* errors found in config file */
  111. private    int     maxerr;
  112. private    char    *ttype_drop[ NTTYPES ];
  113.  
  114.     /* forward references */
  115. private    void    insert();
  116.  
  117.  
  118. private int ParseLine( line, args )
  119.   register char  *line;
  120.   char           **args;
  121.   {
  122.     register char  c;
  123.     int            ac = 0;
  124.  
  125.     for( ; ; )
  126.       {
  127.     while( (c = *line) <= ' ' and c != '\0' )
  128.         line++;
  129.     if( c == '\0' or c == ';' )
  130.         break;
  131.     *args++ = line;
  132.     ac++;
  133.     while( (c = *line) > ' ' and c != ';' )
  134.         line++;
  135.     *line = '\0';
  136.     if( c == '\0' or c == ';' )
  137.         break;
  138.     line++;
  139.       }
  140.     *line = '\0';
  141.     *args = NULL;
  142.     return( ac );
  143.   }
  144.  
  145.  
  146. public void config( cname )
  147.   char  *cname;
  148.   {
  149.     register pTable  *p;
  150.     FILE             *cfile;
  151.     char             prm_file[256];
  152.     char             line[LSIZE];
  153.     char             *targv[MAXARGS];
  154.     char             tmpbuff[NTTYPES * 22];
  155.     int              targc;
  156.  
  157.     for( targc = 0; targc < NTTYPES; targc++ )
  158.       {
  159.     ttype_drop[ targc ] = &tmpbuff[ targc * 22 ];
  160.     (void) sprintf( ttype_drop[ targc ], "%s-with-drop", ttype[ targc ] );
  161.       }
  162.  
  163.     if( *cname != '/' )        /* not full path specified */
  164.       {
  165.     Fstat  *stat;
  166.     
  167.     stat = FileStatus( cname );
  168.     if( not stat->read )
  169.       {
  170.         (void) sprintf( prm_file, "%s/%s", cad_lib, cname );
  171.         stat = FileStatus( prm_file );
  172.         if( stat->read )
  173.             cname = prm_file;
  174.         else
  175.         {
  176.           (void) sprintf( prm_file, "%s/irsim/%s", cad_lib, cname );
  177.           stat = FileStatus( prm_file );
  178.           if( stat->read )
  179.             cname = prm_file;
  180.           else
  181.               {
  182.             (void) strcat( prm_file, ".prm" );
  183.             stat = FileStatus( prm_file );
  184.             if( stat->read )
  185.                 cname = prm_file;
  186.               }
  187.           }
  188.       }
  189.       }
  190.     currfile = cname;
  191.  
  192.     lineno = 0;
  193.     if( (cfile = fopen( cname, "r" )) == NULL )
  194.       {
  195.     lprintf(stderr,"can't open electrical parameters file <%s>\n", cname);
  196.     exit( 1 );
  197.       }
  198.  
  199.     *line = '\0';
  200.     (void) fgetline( line, LSIZE, cfile );
  201.     if( strncmp( line, "; configuration file", 20 ) )
  202.       {
  203.     rewind( cfile );
  204.     maxerr = 1;
  205.       }
  206.     else
  207.     maxerr = 15;
  208.  
  209.     while( fgetline( line, LSIZE, cfile ) != NULL )
  210.       {
  211.     lineno++;
  212.     targc = ParseLine( line, targv );
  213.     if( targc == 0 )
  214.         continue;
  215.     if( str_eql( "resistance", targv[0] ) == 0 )
  216.       {
  217.         if( targc >= 6 )
  218.         insert( targv[1], targv[2], targv[3], targv[4], targv[5] );
  219.         else
  220.           {
  221.         error( currfile, lineno, "syntax error in resistance spec\n" );
  222.         nerrs++;
  223.           }
  224.         continue;
  225.       }
  226.     else
  227.       {
  228.         for( p = parms; p->name != NULL; p++ )
  229.           {
  230.         if( str_eql( p->name, targv[0] ) == 0 )
  231.           {
  232.             if( p->dptr != NULL )
  233.             *(p->dptr) = atof( targv[1] );
  234.             if( p->flag != 0 and atoi( targv[1] ) != 0 )
  235.             config_flags |= p->flag;
  236.             break;
  237.           }
  238.           }
  239.         if( p->name == NULL )
  240.           {
  241.         error( currfile, lineno,
  242.           "unknown electrical parameter: (%s)\n", targv[0] );
  243.         nerrs++;
  244.           }
  245.       }
  246.     if( nerrs >= maxerr )
  247.       {
  248.         if( maxerr == 1 )
  249.         lprintf( stderr,
  250.           "I think %s is not an electrical parameters file\n", cname );
  251.         else
  252.         lprintf( stderr, "Too many errors in '%s'\n", cname );
  253.         exit( 1 );
  254.       }
  255.       }
  256.     LAMBDA2 = LAMBDA * LAMBDA;
  257.     LAMBDACM = LAMBDA * CM_M;
  258.     CTGA = ( (config_flags & SUBPAREA) ? (CGA - CPA) : CGA ) / (CM_M * CM_M);
  259.     switch( config_flags & (DIFFEXTF | DIFFPERIM) )
  260.       {
  261.     case 0 :
  262.         CTDE = CTDW = 0.0;    break;
  263.     case DIFFPERIM :
  264.         config_flags |= TDIFFCAP;
  265.         CTDE = 0.0;
  266.         CTDW = -(CDP / CM_M);
  267.         break;
  268.     case DIFFEXTF :
  269.         config_flags |= TDIFFCAP;
  270.         CTDE = (2 * DIFFEXT * LAMBDA * CDP);
  271.         CTDW = (CDP + DIFFEXT * LAMBDA * CDA) / CM_M;
  272.         break;
  273.     case (DIFFEXTF | DIFFPERIM) :
  274.         config_flags |= TDIFFCAP;
  275.         CTDE = (2 * DIFFEXT * LAMBDA * CDP);
  276.         CTDW = (DIFFEXT * LAMBDA * CDA) / CM_M;
  277.         break;
  278.       }
  279.  
  280.     if( config_flags & CNTPULLUP )
  281.     lprintf( stderr, "warning: cntpullup is not supported\n" );
  282.  
  283.     (void) fclose( cfile );
  284.   }
  285.  
  286.  
  287. /*
  288.  * info on resistance vs. width and length are stored first sorted by
  289.  * width, then by length.
  290.  */
  291. struct length
  292.   {
  293.     struct length    *next;    /* next element with same width */
  294.     long             l;        /* length of this channel in centimicrons */
  295.     double           r;        /* equivalent resistance/square */
  296.   };
  297.  
  298. struct width
  299.   {
  300.     struct width     *next;    /* next width */
  301.     long             w;        /* width of this channel in centimicrons */
  302.     struct length    *list;    /* list of length structures */
  303.   } *resistances[ R_TYPES ][ NTTYPES ];
  304.  
  305.  
  306. /* linear interpolation, assume that x1 < x <= x2 */
  307. #define    interp( x, x1, y1, x2, y2 )  \
  308.   ( (((double) (x - x1)) / ((double) (x2 - x1))) * (y2 - y1) + y1 )
  309.  
  310.  
  311. /*
  312.  * given a list of length structures, sorted by incresing length return
  313.  * resistance of given channel.  If no exact match, return result of
  314.  * linear interpolation using two closest channels.
  315.  */
  316. private double lresist( list, l, size )
  317.   register struct length  *list;
  318.   long                    l;
  319.   double                  size;
  320.   {
  321.     register struct length  *p, *q;
  322.  
  323.     for( p = list, q = NULL; p != NULL; q = p, p = p->next )
  324.       {
  325.     if( p->l == l or( p->l > l and q == NULL ) )
  326.         return( p->r * size );
  327.     if( p->l > l )
  328.         return( size * interp( l, q->l, q->r, p->l, p->r ) );
  329.       }
  330.     if( q != NULL )
  331.     return( q->r *size );
  332.     return( 1E4 * size );
  333.   }
  334.  
  335.  
  336. /*
  337.  * given a pointer to the width structures for a particular type of
  338.  * channel compute the resistance for the specified channel.
  339.  */
  340. private double wresist( list, w, l )
  341.   register struct width  *list;
  342.   long                   w, l;
  343.   {
  344.     register struct width  *p, *q;
  345.     double                 size = ((double) l) / ((double) w);
  346.     double                 temp;
  347.  
  348.     for( p = list, q = NULL; p != NULL; q = p, p = p->next )
  349.       {
  350.     if( p->w == w or( p->w > w and q == NULL ) )
  351.         return( lresist( p->list, l, size ) );
  352.     if( p->w > w )
  353.       {
  354.         temp = lresist( q->list, l, size );
  355.         return( interp( w, q->w, temp, p->w, lresist( p->list, l, size ) ) );
  356.       }
  357.       }
  358.     if( q != NULL )
  359.     return( lresist( q->list, l, size ) );
  360.     return( 1E4 * size );
  361.   }
  362.  
  363. typedef struct ResEntry  *resptr;
  364.  
  365. typedef struct ResEntry
  366.   {
  367.     resptr    r_next;
  368.     Resists   r;
  369.   } ResEntry;
  370.  
  371. #define    RES_TAB_SIZE    67
  372.  
  373. /*
  374.  * Compute equivalent resistance given width, length and type of transistor.
  375.  * for all contexts (STATIC, DYNHIGH, DYNLOW).  Place the result on the
  376.  * transistor 
  377.  */
  378. public Resists *requiv( type, width, length )
  379.   int   type;
  380.   long  width, length;
  381.   {
  382.     static resptr    *res_htab[ NTTYPES ];
  383.     static resptr    freeResist;
  384.     resptr           *rtab;
  385.     register resptr  r;
  386.     unsigned         n;
  387.  
  388.     type = BASETYPE( type );
  389.  
  390.     rtab = res_htab[ type ];
  391.     if( rtab == NULL )
  392.       {
  393.     rtab = (resptr *) Valloc( RES_TAB_SIZE * sizeof( resptr * ), 1 );
  394.     for( n = 0; n < RES_TAB_SIZE; rtab[ n++ ] = NULL );
  395.     res_htab[ type ] = rtab;
  396.       }
  397.     n = ((unsigned) (length * 110133 + width)) % RES_TAB_SIZE;
  398.     for( r = rtab[ n ]; r != NULL; r = r->r_next )
  399.       {
  400.     if( r->r.length == length and r->r.width == width ) return( &r->r );
  401.       }
  402.  
  403.     if( (r = freeResist) == NULL )
  404.     r = (resptr) MallocList( sizeof( ResEntry ), 1 );
  405.     freeResist = r->r_next;
  406.     r->r_next = rtab[n];
  407.     rtab[n] = r;
  408.  
  409.     r->r.length = length;
  410.     r->r.width = width;
  411.  
  412.     if( type == RESIST )
  413.       {
  414.     r->r.dynlow = r->r.dynhigh = r->r.rstatic = (float) length / LAMBDACM;
  415.       }
  416.     else
  417.       {
  418.     r->r.rstatic = wresist( resistances[ STATIC ][type], width, length );
  419.     r->r.dynlow = wresist( resistances[ DYNLOW ][type], width, length );
  420.     r->r.dynhigh = wresist( resistances[ DYNHIGH ][type], width, length );
  421.       }
  422.     return( &r->r );
  423.   }
  424.  
  425.  
  426. private void linsert( list, l, resist )
  427.   register struct length  **list;
  428.   long                    l;
  429.   double                  resist;
  430.   {
  431.     register struct length  *p, *q, *lnew;
  432.  
  433.     for( p = *list, q = NULL; p != NULL; q = p, p = p->next )
  434.       {
  435.     if( p->l == l )
  436.       {
  437.         p->r = resist;
  438.         return;
  439.       }
  440.     if( p->l > l )
  441.         break;
  442.       }
  443.     lnew = (struct length *) Valloc( sizeof( struct length ), 1 );
  444.     lnew->next = p;
  445.     lnew->l = l;
  446.     lnew->r = resist;
  447.     if( q == NULL )
  448.     *list = lnew;
  449.     else
  450.     q->next = lnew;
  451.   }
  452.  
  453.  
  454. /* add a new data point to the interpolation array */
  455. private void winsert( list, w, l, resist )
  456.   register struct width  **list;
  457.   long                   w, l;
  458.   double                 resist;
  459.   {
  460.     register struct width   *p, *q, *wnew;
  461.     register struct length  *lnew;
  462.  
  463.     for( p = *list, q = NULL; p != NULL; q = p, p = p->next )
  464.       {
  465.     if( p->w == w )
  466.       {
  467.         linsert( &p->list, l, resist );
  468.         return;
  469.       }
  470.     if( p->w > w )
  471.         break;
  472.       }
  473.     wnew = (struct width *) Valloc( sizeof( struct width ), 1 );
  474.     lnew = (struct length *) Valloc( sizeof( struct length ), 1 );
  475.     wnew->next = p;
  476.     wnew->list = lnew;
  477.     wnew->w = w;
  478.     if( q == NULL )
  479.     *list = wnew;
  480.     else
  481.     q->next = wnew;
  482.     lnew->next = NULL;
  483.     lnew->l = l;
  484.     lnew->r = resist;
  485.   }
  486.  
  487.  
  488. /* interpret resistance specification command */
  489. private void insert( type, context, w, l, r )
  490.   char  *type, *context, *w, *l, *r;
  491.   {
  492.     register int  c, t;
  493.     long          width, length;
  494.     double        resist;
  495.  
  496.     width = atof( w ) * CM_M;
  497.     length = atof( l ) * CM_M;
  498.     resist = atof( r );
  499.     if( width <= 0 or length <= 0 or resist <= 0 )
  500.       {
  501.     error( currfile, lineno, "bad w, l, or r in config file\n" );
  502.     nerrs++;
  503.     return;
  504.       }
  505.  
  506.     if( str_eql( context, "static" ) == 0 )
  507.     c = STATIC;
  508.     else if( str_eql( context, "dynamic-high" ) == 0 )
  509.     c = DYNHIGH;
  510.     else if( str_eql( context, "dynamic-low" ) == 0 )
  511.     c = DYNLOW;
  512.     else if( str_eql( context, "power" ) == 0 )
  513.     c = POWER;
  514.     else
  515.       {
  516.     error( currfile, lineno, "bad resistance context in config file\n" );
  517.     nerrs++;
  518.     return;
  519.       }
  520.  
  521.     for( t = 0; t < NTTYPES; t++ )
  522.       {
  523.     if( str_eql( ttype[t], type ) == 0 )
  524.       {
  525.         if( c == POWER )
  526.         return;
  527.         winsert( &resistances[c][t], width, length, resist*width/length );
  528.         return;
  529.       }
  530.     else if( str_eql( ttype_drop[t], type ) == 0 )
  531.         return;
  532.       }
  533.  
  534.     error( currfile, lineno, "bad resistance transistor type\n" );
  535.     nerrs++;
  536.   }
  537.  
  538.